/*
 * Copyright : (C) 2022 Phytium Information Technology, Inc. 
 * All Rights Reserved.
 *  
 * This program is OPEN SOURCE software: you can redistribute it and/or modify it  
 * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,  
 * either version 1.0 of the License, or (at your option) any later version. 
 *  
 * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;  
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Phytium Public License for more details. 
 *  
 * 
 * FilePath: canfd_box_example.c
 * Date: 2023-12-05 16:05:49
 * LastEditTime: 2023-12-05 16:05:49
 * Description:  This file is for can box test 
 * 
 * Modify History: 
 *  Ver Who      Date        Changes
 * ----- ------     --------    --------------------------------------
 * 1.0   huangjin   2023/12/05  first release
 */

#include <stdio.h>
#include <string.h>
#include "fcpu_info.h"
#include "fparameters.h"
#include "fcan_simple.h"
#include "fio_mux.h"
#include "sdkconfig.h"

#define FCAN_SEND_ID 0x123
#define FCAN_SEND_LENGTH 16

static u32 SendFrame(FCanCtrl *instance_p, boolean ide);
static u32 RecvFrame(FCanCtrl *instance_p);

/************************** Variable Definitions ****************************/
static FCanCtrl can[FCAN_NUM];

static FError SendFrame(FCanCtrl *instance_p, boolean ide)
{
    u8 i = 0;
    FError ret;
	FCanFrame frame;
	frame.canid = FCAN_SEND_ID;
	if (ide == 1)
	{
		frame.canid |= CAN_EFF_FLAG;
	}	
	else
	{
		frame.canid &= CAN_SFF_MASK;
	}
    frame.candlc = FCAN_SEND_LENGTH;
	printf("can send id is %#x\r\n", frame.canid);
	printf("can send dlc is %d\r\n", frame.candlc);   
	printf("can send data is ");
    for (i = 0; i < frame.candlc; i++)
    {
        frame.data[i] = i;
		printf("%#x ", frame.data[i]);
    }
	printf("\r\n");

    ret = FCanSend(instance_p, &frame);
	if(ret == FCAN_FAILURE)
	{
		printf("\n send error \n");
	}
    return ret;
}

static FError RecvFrame(FCanCtrl *instance_p)
{
    u8 i;
    FError ret;
	int timeout = 100;
	FCanFrame frame = {0};
	while (FCAN_RX_FIFO_EMPTY(instance_p->config.base_address) && (timeout > 0))
	{
		timeout--;
		for (volatile int i = 0; i < 10000000; i++);
	}
	if(timeout <= 0)
	{
		printf("Can recv wait timeout, please send can frame.\r\n");
		return 0;
	}
	ret = FCanRecv(instance_p, &frame);
    if (FCAN_SUCCESS == ret)
    {
        printf("can recv id is %#x\r\n", frame.canid);
        printf("can recv dlc is %d\r\n", frame.candlc);   
		printf("can recv data is ");
        for (i = 0; i < frame.candlc; i++)
        {
			printf("%#x ", frame.data[i]);
		}
		printf("\r\n");
	}
    return ret;
}

u32 FCanfdBoxTestExample(u32 can_id, u32 arb_baud, u32 data_baud, boolean ide, u32 send_times, u32 recv_times)
{
    FError ret = FCAN_SUCCESS;
    int i = 0;

    printf("Use canfd protocol!\n");

    /*init iomux*/
    FIOMuxInit();
	FIOPadSetCanMux(can_id);

	ret = FCanCfgInitialize(&can[can_id], FCanLookupConfig(can_id));
	if (ret != FCAN_SUCCESS)
	{
		printf("\nCan%d Initialize error.\n", can_id);
		goto exit;
	}

	/*enable canfd, configured as canfd mode*/
	FCanFdEnable(&can[can_id], TRUE);

	/*set to normal mode*/
	FCanSetMode(&can[can_id] , 0);

    /*set baud rate*/
    FCanBaudrateConfig arb_segment_config;
    FCanBaudrateConfig data_segment_config;
    memset(&arb_segment_config, 0, sizeof(arb_segment_config));
    memset(&data_segment_config, 0, sizeof(data_segment_config));

    arb_segment_config.baudrate = arb_baud;
    arb_segment_config.auto_calc = TRUE;
    arb_segment_config.segment = FCAN_ARB_SEGMENT;

    data_segment_config.baudrate = data_baud;
    data_segment_config.auto_calc = TRUE;
    data_segment_config.segment = FCAN_DATA_SEGMENT;

	ret = FCanBaudrateSet(&can[can_id], &arb_segment_config);
	ret = FCanBaudrateSet(&can[can_id], &data_segment_config);
	
	FCanIdMaskConfig id_mask;
	FCanEnable(&can[can_id], FALSE);
	memset(&id_mask, 0, sizeof(id_mask));
	for (i = 0; i < FCAN_ACC_ID_REG_NUM; i++)
	{
		id_mask.filter_index = i;
		id_mask.id = 0;
		id_mask.mask = FCAN_ACC_IDN_MASK;
		id_mask.type = STANDARD_FRAME;
		ret |= FCanIdMaskFilterSet(&can[can_id], &id_mask);
	}
	if (ret != FCAN_SUCCESS)
	{
		goto exit;
	}

	/* Identifier mask enable */
	FCanIdMaskFilterEnable(&can[can_id]);

	/*can enable*/
	FCanEnable(&can[can_id], TRUE);

	printf("Can%d initialization succeeded.\r\n", can_id);
	printf("Arbitration field baud rate:%d\r\n", arb_baud);
	printf("Data field baud rate:%d\r\n", data_baud);

	while(1)
	{
		/* send test */
	    if(can[can_id].is_ready != FT_COMPONENT_IS_READY)
	    {
			printf("\n 55 enter if(can[can_id].is_ready != FT_COMPONENT_IS_READY)\n");
		    goto exit;
	    }
	    for(i = 0; i < send_times; i++)
	    {
			printf("\n ide = %d \n",ide);
		    ret = SendFrame(&can[can_id], ide);
		    if (ret != 0)
		    {
			    goto exit;
		    }
		    printf("Send canfd frame %d times.\r\n", i + 1);
		    for (volatile int i = 0; i < 100000000; i++);
	    }

	    /* recv test */
	    if(can[can_id].is_ready != FT_COMPONENT_IS_READY)
	    {
		    goto exit;
	    }
	    printf("Wait for the can box to send data %d times!!!\r\n", recv_times);
	    for(i = 0; i < recv_times; i++)
	    {
		    ret = RecvFrame(&can[can_id]);
		    if (ret != 0)
		    {
			    goto exit;
		    }
	    }
		for (volatile int i = 0; i < 100000000; i++);
	}
	
	/* deinit can */
	FCanDeInitialize(&can[can_id]);

exit:
	return ret;
}

int main(void)
{
    FCanfdBoxTestExample(0,1000000,1000000,0,1,1);

    return 0;
}

